"""
优化的头皮策略实现
支持参数优化和自适应调整
"""
import pandas as pd
import numpy as np
from typing import Dict, Tuple, Optional
from src.strategy.base import BaseStrategy
from src.strategy.indicators import Indicators
from src.strategy.parameter_optimizer import StrategyParams, AdaptiveParameterAdjuster
from src.utils.logger import get_logger

logger = get_logger(__name__)


class OptimizedScalpingStrategy(BaseStrategy):
    """
    优化的头皮策略

    改进点:
    1. 支持参数优化
    2. 自适应参数调整
    3. 多指标增强确认
    4. 动态信心度计算
    """

    def __init__(self, config: Dict, params: Optional[StrategyParams] = None):
        """初始化"""
        super().__init__(config)

        # 策略参数
        self.params = params or StrategyParams()
        self.adaptive_adjuster = AdaptiveParameterAdjuster(self.params)

        # 指标计算器
        self.indicators = Indicators()

        logger.info(f"策略参数: {self.params.to_dict()}")

    def update_params(self, params: StrategyParams):
        """更新策略参数"""
        self.params = params
        self.adaptive_adjuster = AdaptiveParameterAdjuster(params)
        logger.info(f"策略参数已更新: {params.to_dict()}")

    def generate_signal(self, kline_data: Dict[int, pd.DataFrame]) -> Tuple[str, float]:
        """
        生成交易信号

        Returns:
            (信号: buy/sell/hold, 信心度: 0-1)
        """
        # 验证数据
        if not self._validate_multiframe_data(kline_data):
            return "hold", 0.0

        # 获取各时间框架的数据
        df_5m = kline_data.get(5)
        df_15m = kline_data.get(15)
        df_1h = kline_data.get(60)
        df_4h = kline_data.get(240)

        # 自适应调整参数
        if df_5m is not None:
            self.adaptive_adjuster.adjust_parameters(df_5m)

        # 获取当前参数
        current_params = self.adaptive_adjuster.get_current_params()

        # 分析各时间框架
        signal_4h, strength_4h = self._analyze_timeframe(
            df_4h, current_params, "4H"
        )
        signal_1h, strength_1h = self._analyze_timeframe(
            df_1h, current_params, "1H"
        )
        signal_15m, strength_15m = self._analyze_timeframe(
            df_15m, current_params, "15M"
        )
        signal_5m, strength_5m = self._analyze_timeframe(
            df_5m, current_params, "5M"
        )

        # 多时间框架一致性检查
        if not self._check_alignment(signal_4h, signal_1h, signal_15m, signal_5m):
            return "hold", 0.0

        # 检查入场信号
        entry_signal = self._check_entry_signal(df_5m, current_params)

        if entry_signal == "hold":
            return "hold", 0.0

        # 计算综合信心度
        confidence = self._calculate_advanced_confidence(
            signal_4h, strength_4h,
            signal_1h, strength_1h,
            signal_15m, strength_15m,
            signal_5m, strength_5m,
            entry_signal
        )

        # 检查信心度阈值
        if confidence < current_params.signal_threshold:
            return "hold", confidence

        return entry_signal, confidence

    def _analyze_timeframe(self, df: Optional[pd.DataFrame], params: StrategyParams,
                          timeframe_name: str) -> Tuple[str, float]:
        """
        分析单个时间框架

        Returns:
            (方向: long/short/none, 强度: 0-1)
        """
        if df is None or len(df) < max(params.ema_slow_period, params.rsi_period) + 5:
            return "none", 0.0

        # 计算指标
        rsi = Indicators.calculate_rsi(df['close'].values, params.rsi_period)
        ema_fast = Indicators.calculate_ema(df['close'].values, params.ema_fast_period)
        ema_slow = Indicators.calculate_ema(df['close'].values, params.ema_slow_period)
        macd, signal_line, histogram = Indicators.calculate_macd(
            df['close'].values,
            params.macd_fast,
            params.macd_slow,
            params.macd_signal
        )
        bb_middle, bb_upper, bb_lower = Indicators.calculate_bollinger_bands(
            df['close'].values,
            params.bb_period,
            params.bb_std
        )

        # 获取最新值（跳过NaN值）
        rsi_latest = self._get_latest_value(rsi)
        ema_fast_latest = self._get_latest_value(ema_fast)
        ema_slow_latest = self._get_latest_value(ema_slow)
        macd_latest = self._get_latest_value(macd)
        signal_latest = self._get_latest_value(signal_line)
        histogram_latest = self._get_latest_value(histogram)
        bb_middle_latest = self._get_latest_value(bb_middle)
        bb_upper_latest = self._get_latest_value(bb_upper)
        bb_lower_latest = self._get_latest_value(bb_lower)
        close_latest = df['close'].iloc[-1]

        # 如果没有有效的指标值，返回无信号
        if (pd.isna(rsi_latest) or pd.isna(ema_fast_latest) or pd.isna(ema_slow_latest) or
            pd.isna(macd_latest) or pd.isna(signal_latest) or pd.isna(histogram_latest) or
            pd.isna(bb_middle_latest)):
            return "none", 0.0

        # 判断方向
        direction = "none"
        strength = 0.0

        # 多头信号
        long_conditions = 0

        # 条件1: EMA排列 (快线 > 慢线)
        if ema_fast_latest > ema_slow_latest:
            long_conditions += 1

        # 条件2: MACD正值且柱状图为正
        if macd_latest > 0 and histogram_latest > 0:
            long_conditions += 1

        # 条件3: RSI低于70但在50以上
        if 50 < rsi_latest < 70:
            long_conditions += 1

        # 条件4: 价格在布林带中点上方
        if close_latest > bb_middle_latest:
            long_conditions += 1

        # 条件5: 超卖反弹信号
        if rsi_latest < params.rsi_oversold:
            long_conditions += 1

        if long_conditions >= 3:
            direction = "long"
            # 强度基于满足的条件数量和RSI距离
            strength = min(long_conditions / 5.0 * 1.2, 1.0)
            if rsi_latest < params.rsi_oversold:
                strength = min(strength * 1.2, 1.0)

        # 空头信号
        short_conditions = 0

        # 条件1: EMA排列 (快线 < 慢线)
        if ema_fast_latest < ema_slow_latest:
            short_conditions += 1

        # 条件2: MACD负值且柱状图为负
        if macd_latest < 0 and histogram_latest < 0:
            short_conditions += 1

        # 条件3: RSI高于30但在50以下
        if 30 < rsi_latest < 50:
            short_conditions += 1

        # 条件4: 价格在布林带中点下方
        if close_latest < bb_middle_latest:
            short_conditions += 1

        # 条件5: 超买回落信号
        if rsi_latest > params.rsi_overbought:
            short_conditions += 1

        if short_conditions >= 3:
            direction = "short"
            # 强度基于满足的条件数量和RSI距离
            strength = min(short_conditions / 5.0 * 1.2, 1.0)
            if rsi_latest > params.rsi_overbought:
                strength = min(strength * 1.2, 1.0)

        return direction, strength

    def _check_alignment(self, dir_4h: str, dir_1h: str,
                        dir_15m: str, dir_5m: str) -> bool:
        """检查多时间框架对齐"""
        # 4H为主要方向
        if dir_4h == "none":
            # 如果4H没有信号，至少需要1H和15M同向
            if dir_1h == "none" or dir_15m == "none":
                return False
            if dir_1h != dir_15m:
                return False
            return True

        # 1H必须与4H同向
        if dir_1h != "none" and dir_1h != dir_4h:
            return False

        # 15M和5M应该同向
        if dir_15m != "none" and dir_5m != "none" and dir_15m != dir_5m:
            return False

        return True

    def _check_entry_signal(self, df_5m: pd.DataFrame, params: StrategyParams) -> str:
        """
        检查5分钟入场信号

        更敏感的入场判断
        """
        if len(df_5m) < 3:
            return "hold"

        # 计算指标
        rsi = Indicators.calculate_rsi(df_5m['close'].values, params.rsi_period)
        macd, signal, histogram = Indicators.calculate_macd(
            df_5m['close'].values,
            params.macd_fast,
            params.macd_slow,
            params.macd_signal
        )

        rsi_current = self._get_latest_value(rsi)
        rsi_prev = self._get_latest_value(rsi[:-1]) if len(rsi) > 1 else np.nan
        histogram_current = self._get_latest_value(histogram)
        histogram_prev = self._get_latest_value(histogram[:-1]) if len(histogram) > 1 else np.nan

        # 检查是否有有效值
        if pd.isna(rsi_current) or pd.isna(histogram_current):
            return "hold"

        # 买入信号
        # 1. RSI从超卖反弹
        if not pd.isna(rsi_prev) and rsi_prev <= params.rsi_oversold and rsi_current > rsi_prev:
            return "buy"

        # 2. MACD金叉
        if not pd.isna(histogram_prev) and histogram_prev <= 0 and histogram_current > 0:
            return "buy"

        # 卖出信号
        # 1. RSI从超买回落
        if not pd.isna(rsi_prev) and rsi_prev >= params.rsi_overbought and rsi_current < rsi_prev:
            return "sell"

        # 2. MACD死叉
        if not pd.isna(histogram_prev) and histogram_prev >= 0 and histogram_current < 0:
            return "sell"

        return "hold"

    def _calculate_advanced_confidence(self, dir_4h: str, str_4h: float,
                                     dir_1h: str, str_1h: float,
                                     dir_15m: str, str_15m: float,
                                     dir_5m: str, str_5m: float,
                                     signal_5m: str) -> float:
        """
        计算高级信心度

        基于:
        1. 多时间框架强度
        2. 时间框架一致性
        3. 入场信号质量
        """
        if signal_5m == "hold":
            return 0.0

        # 基础信心度
        base_confidence = 0.5

        # 时间框架权重和强度
        weights = {
            240: self.params.tf_4h_weight,
            60: self.params.tf_1h_weight,
            15: self.params.tf_15m_weight,
            5: self.params.tf_5m_weight,
        }

        strengths = {
            240: str_4h if dir_4h != "none" else 0,
            60: str_1h if dir_1h != "none" else 0,
            15: str_15m if dir_15m != "none" else 0,
            5: str_5m if dir_5m != "none" else 0,
        }

        # 加权强度
        weighted_strength = sum(strengths[tf] * weights[tf] for tf in weights)

        # 一致性奖励
        consistency_bonus = 0.0
        if dir_4h != "none" and dir_1h != "none" and dir_4h == dir_1h:
            consistency_bonus += 0.1

        if dir_15m != "none" and dir_5m != "none" and dir_15m == dir_5m:
            consistency_bonus += 0.1

        # 综合信心度
        confidence = base_confidence + weighted_strength * 0.3 + consistency_bonus

        return min(confidence, 1.0)

    def _get_latest_value(self, arr: np.ndarray) -> float:
        """
        获取数组的最新有效值（跳过NaN）

        Args:
            arr: numpy数组

        Returns:
            最新的非NaN值，或NaN如果都是NaN
        """
        if arr is None or len(arr) == 0:
            return np.nan

        # 从末尾向前查找第一个非NaN值
        for i in range(len(arr) - 1, -1, -1):
            val = arr[i]
            # 转换为标量值
            if isinstance(val, np.ndarray):
                val = float(val)
            if not pd.isna(val):
                return float(val)

        return np.nan

    def _validate_multiframe_data(self, kline_data: Dict[int, pd.DataFrame]) -> bool:
        """验证多时间框架数据"""
        if not kline_data or len(kline_data) == 0:
            return False

        # 至少需要5分钟数据
        if 5 not in kline_data:
            return False

        df_5m = kline_data[5]
        if df_5m is None or len(df_5m) < max(self.params.ema_slow_period, 20):
            return False

        return True
